package com.td.server.state;

import java.util.Iterator;
import java.util.LinkedList;

import com.td.core.communication.obj.GameStateInfo.STATE;
import com.td.core.globals.TDGlobals;
import com.td.core.messages.MessageLogic;
import com.td.core.obj.Player;
import com.td.core.obj.TDGame;
import com.td.core.obj.TDMap;
import com.td.core.obj.TDPoint;
import com.td.core.obj.bullet.Bullet;
import com.td.core.obj.logic.BulletLogic;
import com.td.core.obj.logic.LevelLogic;
import com.td.core.obj.tower.Tower;
import com.td.core.obj.unit.Unit;
import com.td.core.obj.utils.PointConverter;
import com.td.core.obj.utils.TDTimer2;
import com.td.core.pathfinding.IPathfinding;
import com.td.core.pathfinding.PathPoint;
import com.td.core.pathfinding.RiskAStar;
import com.td.core.pathfinding.exception.PathNotFoundException;

public class ActionState extends State {

	protected TDTimer2 unitTimer;
	protected boolean createdUnits;
	private int level;
	
	protected LevelLogic ll;
	
	public ActionState(TDGame game) {
		super(game);
		unitTimer = new TDTimer2(1);
		ll = new LevelLogic();
	}

	@Override
	public void init(int level) {
		game.getStateInfo().setCurrentState(STATE.ACTION);
		game.getStateInfo().setCurrentLevel(level);
		this.level = level;
		createdUnits = false;
		unitTimer.restart();
		setEnd(false);
		
		MessageLogic.addMessageToAll(game, "Level " + level + "!");
	}
	
	@Override
	public void update() {

		if(unitTimer.update() && !createdUnits) {
			createUnits();
			createdUnits = true;
		}
		
		if(!createdUnits)
			return;
		
		for(Player player : game.getPlayers()) {
			if(!player.isGameOver()) {
				updateUnits(player);
				updateTowers(player);
				updateBullets(player);
			} else {
				player.getUnits().clear();
				player.getBullets().clear();
				player.getUnits().clear();
			}
		}
		
		setEnd(checkIfActionEnds());
	}
	
	protected void updateUnits(Player player) {
		Iterator<Unit> iUnit = player.getUnits().iterator();	
		while(iUnit.hasNext()) {
			
			Unit u = iUnit.next();
			u.move();
			
			if(u.getRealPosition().equals(
					PointConverter.toTDVector(TDGlobals.unitTarget), TDMap.DrawParams.FIELD_SIZE)) {
				iUnit.remove();
				player.passUnit();
				player.getStats().incrementPassedUnits();
				continue;
			}
			
			if(u.isDead()) {
				iUnit.remove();
				
				int points = 10;
				player.addPoints(points);
				player.getStats().addPoint(points);
				
				int award = (int) u.getAward();
				player.addGold(award);
				player.getStats().addGold(award);
				
				
				player.getStats().incrementKilledUnits();
				continue;
			}
		}
		
		if(player.getPassedUnits() >= TDGlobals.maxPassedUnits)
			player.setGameOver(true);
	}
	
	protected void updateTowers(Player player) {
		Iterator<Tower> iTower = player.getTowers().iterator();
		while(iTower.hasNext()) {
			
			Tower t = iTower.next();
			
			Unit attackedUnit = t.attack(player.getUnits());
			if(attackedUnit != null){
				
				BulletLogic.addBullet(player, t.createBullet(attackedUnit) );
				player.getStats().incrementTotalBullet();
			}
			
		}
	}
	
	protected void updateBullets(Player player) {
		Iterator<Bullet> iBullet = player.getBullets().iterator();
		while(iBullet.hasNext()) {
			
			Bullet b = iBullet.next();
			b.move();
			
			if(b.isGoal()) {
								
				for(Unit unit : player.getUnits()) {

					if(!unit.equals(b.getAttackedUnit())) {
						
						float distance = unit.getRealPosition().distance(b.getRealPosition());
						if(distance < b.getSplash() * TDMap.DrawParams.FIELD_SIZE) {
							int damage =  (int) (b.getDamage() / ((distance / TDMap.DrawParams.FIELD_SIZE) + 1) ); 
							unit.deacreaseLife(damage);
						}
					}
				}
				
				iBullet.remove();
			}
			
		}
	}
	
	protected boolean checkIfActionEnds() {
		
		for(Player player : game.getPlayers()) {
			if(!player.getUnits().isEmpty())
				return false;
			else
				player.getBullets().clear();
		}

		return true;
		
	}
	
	protected LinkedList<TDPoint> calculatePath(TDPoint start, TDPoint target, int player) {
		
		IPathfinding aStar = new RiskAStar();
		
		int[][] map = new int[TDMap.MAP_X][TDMap.MAP_Y];

		for(int i = 0 ; i < TDMap.MAP_X ; i++)
			for(int j = 0 ; j < TDMap.MAP_Y ; j++)
				map[i][j] = 0;
		
		for(Tower tower : game.getPlayers()[player].getTowers()) {
			
			int x = tower.getPosition().getX();
			int y = tower.getPosition().getY();
			for(int i = 0 ; i < tower.getSize() ; i++)
				for(int j = 0 ; j < tower.getSize() ; j++)
					map[x + i][y + j] = IPathfinding.OBSTACLE;
			
		}
		
		PathPoint ppStart = PointConverter.toPathPoint(start);
		PathPoint ppTarget = PointConverter.toPathPoint(target);
		
		
		LinkedList<TDPoint> path = new LinkedList<TDPoint>();
		
		try {
			for(PathPoint pathPoint :  aStar.find(ppStart, ppTarget, map))				
				path.add(PointConverter.toTDPoint(pathPoint));
		
		} catch (PathNotFoundException e) {
			
			//TODO 
			//cos z tym trzeba zrobic
			e.printStackTrace();
		}
		return path;
	}
	
	protected void createUnits() {
		
		for(Player player: game.getPlayers()){
			if(!player.isGameOver())
				ll.createUnits(player, level);
		}
	}
}
